﻿#include <QImage>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QApplication>
#include <QDebug>
#include <QStringList>
#include <QSettings>

#include <GSLAM/core/Svar.h>
#include <GSLAM/core/Glog.h>
#include <GSLAM/core/Timer.h>
#include <GSLAM/core/Utils_LZ4.h>

#include "QtUtils.h"



int clearnDir(const QString& dPath)
{
    QDir tempDir(dPath);

//    if( tempDir.exists() )
//        tempDir.remove();

    tempDir.mkdir(tempDir.absolutePath());

    return 0;
}



QString GetHttpResponse(const QString& url, int timeout)
{
    double ts = 0.05, ta = 0.0;
    GSLAM::Rate r(1.0/ts);

    QNetworkRequest request;
    request.setUrl(QUrl(url));
    QNetworkAccessManager *manager = new QNetworkAccessManager(NULL);
    QNetworkReply *reply = manager->get(request);

    while( !reply->isFinished() ) {
        r.sleep();

        ta += ts;
        if( ta > timeout ) return "";

        QApplication::processEvents();
    }

    QByteArray data = reply->readAll();
    QString s = QString::fromUtf8(data.data()).trimmed();

    return s;
}


////////////////////////////////////////////////////////////////////////////////
/// System utils
////////////////////////////////////////////////////////////////////////////////

#if defined(_WIN32)
#include <Windows.h>

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#if defined(BSD)
#include <sys/sysctl.h>
#endif

#else
#error "Unable to define getMemorySize( ) for an unknown OS."
#endif



/**
 * Returns the size of physical memory (RAM) in bytes.
 */
size_t getMemorySize( )
{
#if defined(_WIN32) && (defined(__CYGWIN__) || defined(__CYGWIN32__))
    /* Cygwin under Windows. ------------------------------------ */
    /* New 64-bit MEMORYSTATUSEX isn't available.  Use old 32.bit */
    MEMORYSTATUS status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatus( &status );
    return (size_t)status.dwTotalPhys;

#elif defined(_WIN32)
    /* Windows. ------------------------------------------------- */
    /* Use new 64-bit MEMORYSTATUSEX, not old 32-bit MEMORYSTATUS */
    MEMORYSTATUSEX status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatusEx( &status );
    return (size_t)status.ullTotalPhys;

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
    /* UNIX variants. ------------------------------------------- */
    /* Prefer sysctl() over sysconf() except sysctl() HW_REALMEM and HW_PHYSMEM */

#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
    int mib[2];
    mib[0] = CTL_HW;
#if defined(HW_MEMSIZE)
    mib[1] = HW_MEMSIZE;            /* OSX. --------------------- */
#elif defined(HW_PHYSMEM64)
    mib[1] = HW_PHYSMEM64;          /* NetBSD, OpenBSD. --------- */
#endif
    int64_t size = 0;               /* 64-bit */
    size_t len = sizeof( size );
    if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 )
        return (size_t)size;
    return 0L;			/* Failed? */

#elif defined(_SC_AIX_REALMEM)
    /* AIX. ----------------------------------------------------- */
    return (size_t)sysconf( _SC_AIX_REALMEM ) * (size_t)1024L;

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
    /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
    return (size_t)sysconf( _SC_PHYS_PAGES ) *
        (size_t)sysconf( _SC_PAGESIZE );

#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGE_SIZE)
    /* Legacy. -------------------------------------------------- */
    return (size_t)sysconf( _SC_PHYS_PAGES ) *
        (size_t)sysconf( _SC_PAGE_SIZE );

#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
    /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
    int mib[2];
    mib[0] = CTL_HW;
#if defined(HW_REALMEM)
    mib[1] = HW_REALMEM;		/* FreeBSD. ----------------- */
#elif defined(HW_PYSMEM)
    mib[1] = HW_PHYSMEM;		/* Others. ------------------ */
#endif
    unsigned int size = 0;		/* 32-bit */
    size_t len = sizeof( size );
    if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 )
        return (size_t)size;
    return 0L;			/* Failed? */
#endif /* sysctl and sysconf variants */

#else
    return 0L;			/* Unknown OS. */
#endif
}

QNetworkTime::QNetworkTime()
{
    QVector<QString> hostList;

    hostList.push_back("time.windows.com");
    hostList.push_back("time.nist.gov");

    udpsocket.connectToHost(hostList.at(0), 123);

    connect(&udpsocket,SIGNAL(connected()),this,SLOT(connectSucess()));
    connect(&udpsocket,SIGNAL(readyRead()),this,SLOT(readingData()));

    timeReaded = 0;
}

QNetworkTime::~QNetworkTime()
{

}

void QNetworkTime::connectSucess()
{
    qint8 LI=0;
    qint8 VN=3;
    qint8 MODE=3;
    qint8 STRATUM=0;
    qint8 POLL=4;
    qint8 PREC=-6;
    QDateTime epoch(QDate(1900,1,1));
    qint32 second=quint32(epoch.secsTo(QDateTime::currentDateTime()));
    qint32 temp=0;

    QByteArray timeRequest(48, 0);
    timeRequest[0]=(LI <<6) | (VN <<3) | (MODE);
    timeRequest[1]=STRATUM;
    timeRequest[2]=POLL;
    timeRequest[3]=PREC & 0xff;
    timeRequest[5]=1;
    timeRequest[9]=1;
    timeRequest[40]=(temp=(second&0xff000000)>>24);
    temp=0;
    timeRequest[41]=(temp=(second&0x00ff0000)>>16);
    temp=0;
    timeRequest[42]=(temp=(second&0x0000ff00)>>8);
    temp=0;
    timeRequest[43]=((second&0x000000ff));

    udpsocket.flush();
    udpsocket.write(timeRequest);
    udpsocket.flush();
}

void QNetworkTime::readingData()
{
    QByteArray newTime;
    QDateTime epoch(QDate(1900, 1, 1));
    QDateTime unixStart(QDate(1970, 1, 1));

    do
    {
        newTime.resize(udpsocket.pendingDatagramSize());
        udpsocket.read(newTime.data(), newTime.size());
    }
    while(udpsocket.hasPendingDatagrams());

    udpsocket.disconnectFromHost();
    udpsocket.close();


    QByteArray TransmitTimeStamp ;
    TransmitTimeStamp=newTime.right(8);
    quint32 seconds=TransmitTimeStamp[0];
    quint8 temp=0;
    for(int j=1;j<=3;j++)
    {
        seconds=seconds<<8;
        temp=TransmitTimeStamp[j];
        seconds=seconds+temp;
    }

    webTime.setTime_t(seconds-epoch.secsTo(unixStart));
    timeReaded = 1;
}

int GetWebDateTime(QDateTime& dt, int timeOut)
{
    QNetworkTime nt;
    GSLAM::Rate r(30);

    int n = 0;
    while( 1 )
    {
        if( nt.isTimeReaded() )
        {
            nt.getDateTime(dt);
            return 0;
        }

        if( n++ > timeOut*30 ) return -1;

        QApplication::processEvents();

        r.sleep();
    }
}
